//--Class 1/8 App_20210530131152 class App_20210530131152 { constructor( canvasId ) { this.timerMs = 100; this.cc = document.getElementById( canvasId ).getContext( "2d" ); this.cc.canvas.style.width = "50%"; this.cc.canvas.style.minHeight = "16px"; this.cc.canvas.width = 512; this.cc.canvas.app = this; this.cc.canvas.onclick = this.reset.bind( this ); this.scale = 2; this.horizon = 0.9; //---canvas臨時拡張メソッド this.cc.tmp = { circle : function( x, y, r, fillStyle, strokeStyle ) { this.cc.beginPath(); this.cc.arc( x, y, r, 0, 6.28, false ); this.cc.closePath(); if( fillStyle ) { this.cc.fillStyle = fillStyle; this.cc.fill(); } if( strokeStyle ) { this.cc.strokeStyle = strokeStyle; this.cc.stroke(); } }.bind( this ), line : function( sx, sy, ex, ey, color ) { this.cc.beginPath(); this.cc.moveTo( sx, sy ); this.cc.lineTo( ex, ey ); if( color ) this.cc.strokeStyle = color; this.cc.stroke(); }.bind( this ), clearAll : function() { this.cc.clearRect( - this.cc.canvas.width / this.scale / 2, this.cc.canvas.height * this.horizon / this.scale, this.cc.canvas.width / this.scale, - this.cc.canvas.height / this.scale ); //debug. 描画領域を確認したいとき if( 0 ) { this.cc.strokeStyle = "red"; this.cc.strokeRect( - this.cc.canvas.width / this.scale / 2, this.cc.canvas.height * this.horizon / this.scale, this.cc.canvas.width / this.scale, - this.cc.canvas.height / this.scale ); } }.bind( this ), }//this.cc.tmp //---各SVC_Part_20210530131152定義 let world = new SVC_Part_20210530131152( "world" ); world.addJoint( "世界>キャラ1", -100, 0 ); world.imgd.visibility = true; world.imgd.type = "horizon"; let hara = new SVC_Part_20210530131152( "腹" ); hara.initialY = 100; hara.imgd.w = 18; hara.imgd.h = 15; hara.imgd.x = -12.5; hara.imgd.y = -15; hara.addJoint( "腹>胸", 0, 0 ); hara.addJoint( "腹>腰", 0, -12 ); let mune = new SVC_Part_20210530131152( "胸" ); mune.imgd.w = 20; mune.imgd.h = 20; mune.imgd.x = -12.5; mune.imgd.y = -5; mune.addJoint( "胸>首", 1, 14 ); mune.addJoint( "胸>左上腕", 1, 14 ); let jouwanL = new SVC_Part_20210530131152( "左上腕" ); jouwanL.imgd.w = 10; jouwanL.imgd.h = 23; jouwanL.imgd.x = -5; jouwanL.imgd.y = -23; jouwanL.addJoint( "左上腕>左前腕", 2, -20 ); let zenwanL = new SVC_Part_20210530131152( "左前腕" ); zenwanL.imgd.w = 10; zenwanL.imgd.h = 23; zenwanL.imgd.x = -7; zenwanL.imgd.y = -21; zenwanL.addJoint( "左前腕>左手", -2, -20 ); let teL = new SVC_Part_20210530131152( "左手" ); teL.imgd.w = 10; teL.imgd.h = 10; teL.imgd.x = -5; teL.imgd.y = -10; teL.addJoint( "つかみ", 0, -5 ); let kubi = new SVC_Part_20210530131152( "首" ); kubi.imgd.w = 10; kubi.imgd.h = 10; kubi.imgd.x = -6; kubi.imgd.y = -2; kubi.addJoint( "首>頭", 0, 6 ); let atama = new SVC_Part_20210530131152( "頭" ); atama.imgd.w = 20; atama.imgd.h = 20; atama.imgd.x = -13; atama.imgd.y = -1; let kosi = new SVC_Part_20210530131152( "腰" ); kosi.imgd.w = 20; kosi.imgd.h = 15; kosi.imgd.x = -12.5; kosi.imgd.y = -13; kosi.addJoint( "腰>左もも", -2.5, -10 ); let momoL = new SVC_Part_20210530131152( "左もも" ); momoL.imgd.w = 18; momoL.imgd.h = 30; momoL.imgd.x = -10; momoL.imgd.y = -28; momoL.addJoint( "左もも>左すね", -2.5, -27.5 ); let suneL = new SVC_Part_20210530131152( "左すね" ); suneL.imgd.w = 18; suneL.imgd.h = 30; suneL.imgd.x = -6.5; suneL.imgd.y = -28; suneL.addJoint( "左すね>左かかと", 2.5, -25 ); let kakatoL = new SVC_Part_20210530131152( "左かかと" ); kakatoL.imgd.w = 20; kakatoL.imgd.h = 10; kakatoL.imgd.x = -12; kakatoL.imgd.y = -6; kakatoL.addJoint( "左かかと>左つま先", -10, -2 ); kakatoL.addJoint( "あしのうら", -10, -5 ); let tumasakiL = new SVC_Part_20210530131152( "左つま先" ); tumasakiL.imgd.w = 10; tumasakiL.imgd.h = 7; tumasakiL.imgd.x = -10; tumasakiL.imgd.y = -4; tumasakiL.addJoint( "あしのうら", -10, 0 ); let stick = new SVC_Part_20210530131152( "棒" ); stick.imgd.w = 100; stick.imgd.h = 4; stick.imgd.x = 0; stick.imgd.y = 0; stick.addJoint( "先", 90, 2 ); stick.addJoint( "真ん中", 50, 2 ); //---connect //キャラ1 // teL.connect( "つかみ", stick, "先" ); zenwanL.connect( "左前腕>左手", teL ); jouwanL.connect( "左上腕>左前腕", zenwanL ); mune.connect( "胸>左上腕", jouwanL ); kubi.connect( "首>頭", atama ); mune.connect( "胸>首", kubi ); hara.connect( "腹>胸", mune ); hara.connect( "腹>腰", kosi ); kosi.connect( "腰>左もも", momoL ); momoL.connect( "左もも>左すね", suneL ); suneL.connect( "左すね>左かかと", kakatoL ); kakatoL.connect( "左かかと>左つま先", tumasakiL ); hara.adjust( tumasakiL, "あしのうら", { x : { object : world.jointHash[ "世界>キャラ1" ], propertyName : "absoluteX", }, y : { object : world.jointHash[ "世界>キャラ1" ], propertyName : "absoluteY", }, rotation : { object : world, propertyName : "absoluteRotation", }, } ); hara.initialX = -100; //---svcs.push this.svcs = new Array(); this.svcs.push( world ); this.svcs.push( hara ); this.drawings = new Array(); this.drawings.push( this.svcs ); //---poses this.poses = new Object(); let tick = 3.14 / 10; this.poses.chokuritu = new Pose_20210530131152( 1000, this.timerMs, { list : [ //数値: 減らす時計回り 増やす反時計まわり [ hara, "initialRotation", 0 ], [ atama, "initialRotation", tick * 0 ], [ kubi, "initialRotation", tick * 0 ], [ mune, "initialRotation", tick * 0 ], [ kosi, "initialRotation", tick * 0 ], [ momoL, "initialRotation", tick * 0 ], [ suneL, "initialRotation", tick * 0 ], [ kakatoL, "initialRotation", tick * 0 ], [ tumasakiL, "initialRotation", tick * 0 ], [ jouwanL, "initialRotation", tick * 0 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * 0 ], ], } ); this.poses.kagami = new Pose_20210530131152( 500, this.timerMs, { list : [ //数値: 減らす時計回り 増やす反時計まわり [ hara, "initialRotation", 0 ], [ atama, "initialRotation", tick * -.5 ], [ kubi, "initialRotation", tick * 0 ], [ mune, "initialRotation", tick * .5 ], [ kosi, "initialRotation", tick * -1 ], [ momoL, "initialRotation", tick * -1.5 ], [ suneL, "initialRotation", tick * 2.5 ], [ kakatoL, "initialRotation", tick * -1.5 ], [ tumasakiL, "initialRotation", tick * 0 ], [ jouwanL, "initialRotation", tick * -4 ], [ zenwanL, "initialRotation", tick * -2 ], [ teL, "initialRotation", tick * -1 ], ], } ); this.poses.senobi = new Pose_20210530131152( 300, this.timerMs, { list : [ //数値: 減らす時計回り 増やす反時計まわり [ atama, "initialRotation", tick * -1.5 ], [ kubi, "initialRotation", tick * -1 ], [ mune, "initialRotation", tick * -0.5 ], [ kosi, "initialRotation", tick * 0.5 ], [ momoL, "initialRotation", tick * 0.5 ], [ suneL, "initialRotation", tick * 0 ], [ kakatoL, "initialRotation", tick * 2.5 ], [ tumasakiL, "initialRotation", tick * -3 ], [ jouwanL, "initialRotation", tick * -12 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * -1 ], ], } ); //---kiseki this.kiseki = new Graph_20210530131152( "Graph_20210530131152", { f : function( x ) { return -x * x; }, sx : -10, ex : 0, initialX : 0, initialY : 100, zoomX : 1.6, zoomY : 0.1, zoom : 2, visibility : false, } ); // this.kiseki.debug1 = true; this.svcs.unshift( this.kiseki ); this.poses.bridge = new Pose_20210530131152( 1000, this.timerMs, { start : function() { if( ! this.kiseki.flg ) { this.kiseki.initialX = hara.absoluteX; this.kiseki.initialY = hara.absoluteY; this.kiseki.visibility = true; this.kiseki.flg = true; } hara.initialRotation = -tick * .5; hara.adjust( hara, "腹>腰", { x : { object : this.kiseki.jointHash.jointP, propertyName : "absoluteX", }, y : { object : this.kiseki.jointHash.jointP, propertyName : "absoluteY", }, } ); }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ this.kiseki, "px", this.kiseki.ex ], [ hara, "initialRotation", -3.14 / 2 - .1 ], [ atama, "initialRotation", tick * -1 ], [ kubi, "initialRotation", tick * -2 ], [ mune, "initialRotation", -3.14 /10 ], [ kosi, "initialRotation", 3.14 /10 ], [ momoL, "initialRotation", 3.14 /6 ], [ suneL, "initialRotation", 3.14 /4 ], [ kakatoL, "initialRotation", 3.14 /4 ], [ tumasakiL, "initialRotation", -3.14 /4 ], [ jouwanL, "initialRotation", tick * -10 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * 0 ], ], } ); this.poses.sakadachi = new Pose_20210530131152( 1000, this.timerMs, { start : function() { this.kiseki.initialX = hara.jointHash[ "腹>腰" ].absoluteX; this.kiseki.initialY = hara.jointHash[ "腹>腰" ].absoluteY; this.kiseki.sx = 0; this.kiseki.ex = 13; this.kiseki.flg = true; this.kiseki.update(); }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ this.kiseki, "px", 13 ], [ hara, "initialRotation", -3.05 ], [ atama, "initialRotation", tick * -1 ], [ kubi, "initialRotation", tick * -2 ], [ mune, "initialRotation", tick * -0.5 ], [ kosi, "initialRotation", tick * 0.5 ], [ momoL, "initialRotation", tick * 0 ], [ suneL, "initialRotation", tick * 0 ], [ kakatoL, "initialRotation", 3.14 /4 ], [ tumasakiL, "initialRotation", tick * 1 ], [ jouwanL, "initialRotation", tick * -10], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * -0.5 ], ], } ); this.poses.sakadachi2 = new Pose_20210530131152( 200, this.timerMs, { start : function() { hara.adjust( teL, "つかみ", { x : teL.absoluteX, y : teL.absoluteY - 5, } ); this.kiseki.visibility = false; }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ hara, "initialRotation", -3.14 - 0.1 ], [ atama, "initialRotation", tick * -1 ], [ kubi, "initialRotation", tick * -2 ], [ mune, "initialRotation", tick * -0.5 ], [ kosi, "initialRotation", tick * 0 ], [ momoL, "initialRotation", tick * 0 ], [ suneL, "initialRotation", tick * 0 ], [ kakatoL, "initialRotation", 3.14 /4 ], [ tumasakiL, "initialRotation", tick * 1 ], [ jouwanL, "initialRotation", tick * -10], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * -0.5 ], ], } ); this.poses.a_10en_ochiteru = new Pose_20210530131152( 1000, this.timerMs, { start : function() { hara.releaseAdjust(); hara.initialX = hara.absoluteX - 3; hara.initialY = hara.absoluteY + 10; }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ hara, "initialRotation", -5.25 ], [ atama, "initialRotation", tick * .5 ], [ kubi, "initialRotation", tick * 0 ], [ mune, "initialRotation", tick * 1 ], [ kosi, "initialRotation", tick * -1.5 ], [ momoL, "initialRotation", tick * -2.5 ], [ suneL, "initialRotation", tick * 0 ], [ kakatoL, "initialRotation", tick * 0 ], [ tumasakiL, "initialRotation", tick * 0 ], [ jouwanL, "initialRotation", tick * -5 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * -1 ], ], } ); this.poses.ojigi = new Pose_20210530131152( 250, this.timerMs, { start : function() { hara.adjust( tumasakiL, "あしのうら", { x : tumasakiL.absoluteX - 5, y : tumasakiL.absoluteY + 3, } ); }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ hara, "initialRotation", -5.25 ], [ atama, "initialRotation", tick * -.5 ], [ kubi, "initialRotation", tick * 0 ], [ mune, "initialRotation", tick * 1 ], [ kosi, "initialRotation", tick * -1.5 ], [ momoL, "initialRotation", tick * -3 ], // [ suneL, "initialRotation", tick * 0.5 ], // [ kakatoL, "initialRotation", tick * -0.5 ], // [ tumasakiL, "initialRotation", tick * 0 ], [ jouwanL, "initialRotation", tick * -5 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * -1 ], ], } ); //---kiseki2 this.kiseki2 = new Graph_20210530131152( "Graph2", { f : function( x ) { return -2 * x * x; }, sx : -10, ex : 14, initialX : -50, initialY : 100, zoomX : 1.6, zoomY : 0.2, zoom : 2, visibility : false, } ); // this.kiseki2.debug1 = true; this.svcs.unshift( this.kiseki2 ); this.poses.waai = new Pose_20210530131152( 1000, this.timerMs, { start : function() { if( ! this.kiseki2.flg ) { this.kiseki2.initialX = hara.absoluteX + 5; this.kiseki2.initialY = hara.absoluteY - 5; this.kiseki2.visibility = true; this.kiseki2.flg = true; } hara.adjust( hara, "腹>腰", { x : { object : this.kiseki2.jointP, propertyName : "absoluteX", }, y : { object : this.kiseki2.jointP, propertyName : "absoluteY", }, } ); }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ this.kiseki2, "px", -7.75 ], [ atama, "initialRotation", 0], [ kubi, "initialRotation", 0 ], [ mune, "initialRotation", -0.12 ], [ hara, "initialRotation", -6.45 ], [ kosi, "initialRotation", 0.12 ], [ momoL, "initialRotation", 0 ], [ suneL, "initialRotation", 0 ], [ kakatoL, "initialRotation", tick * 4 ], [ tumasakiL, "initialRotation", tick * 1 ], [ jouwanL, "initialRotation", tick * -10 ], [ zenwanL, "initialRotation", tick * -.5 ], [ teL, "initialRotation", tick * -1 ], ], } ); this.poses.sinsin = new Pose_20210530131152( 1000, this.timerMs, { list : [ //数値: 減らす時計回り 増やす反時計まわり [ this.kiseki2, "px", -1 ], [ hara, "initialRotation", -10 ], [ atama, "initialRotation", tick * -.5 ], [ kubi, "initialRotation", tick * -.5 ], [ mune, "initialRotation", tick * -1 ], [ kosi, "initialRotation", tick * .8 ], [ momoL, "initialRotation", tick * 1.5 ], [ suneL, "initialRotation", tick * 1 ], [ kakatoL, "initialRotation", tick * 4 ], [ tumasakiL, "initialRotation", tick * 1 ], [ jouwanL, "initialRotation", tick * 1.5 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * 0 ], ], } ); this.poses.kagami3 = new Pose_20210530131152( 1000, this.timerMs, { list : [ //数値: 減らす時計回り 増やす反時計まわり [ this.kiseki2, "px", 9.8 ], [ hara, "initialRotation", -11.45 ], [ atama, "initialRotation", tick * 0 ], [ kubi, "initialRotation", tick * 0 ], [ mune, "initialRotation", tick * 1 ], [ kosi, "initialRotation", tick * -1.5 ], [ momoL, "initialRotation", tick * -2.5 ], [ suneL, "initialRotation", tick * 0 ], [ kakatoL, "initialRotation", tick * 0 ], [ tumasakiL, "initialRotation", tick * 0 ], [ jouwanL, "initialRotation", tick * -2 ], [ zenwanL, "initialRotation", tick * 0 ], [ teL, "initialRotation", tick * -1 ], ], } ); this.poses.chokuritu2 = new Pose_20210530131152( 1000, this.timerMs, { start : function() { hara.adjust( tumasakiL, "あしのうら", { x : tumasakiL.absoluteX - 10, y : tumasakiL.absoluteY + 1.5, } ); this.kiseki2.visibility = false; tumasakiL.rotation = 0; this.testflg = true; }, list : [ //数値: 減らす時計回り 増やす反時計まわり [ atama, "initialRotation", tick * -.25 ], [ kubi, "initialRotation", tick * -.25 ], [ hara, "initialRotation", -3.15 * 4 ], [ mune, "initialRotation", tick * -.25 ], [ kosi, "initialRotation", tick * .25 ], [ momoL, "initialRotation", tick * .25 ], [ suneL, "initialRotation", 0 ], [ kakatoL, "initialRotation", -.12 ], [ tumasakiL, "initialRotation", 0 ], [ jouwanL, "initialRotation", tick * -10.5 ], [ zenwanL, "initialRotation", tick * -1 ], ], } ); //---/poses //---リサイズ対応 let resizex = function( e ) { console.log( "resizex()" ); let canvas = this.cc.canvas; //(canvasの物理領域について) //ウィンドウリサイズに伴うcanvas高さ変更 if( 0 ) { let H = document.getElementsByTagName( "H1" )[ 0 ]; if( H ) { canvas.style.height = H.offsetTop + "px"; } else { canvas.style.height = window.innerHeight - 48 + "px"; } //※なお、canvas.style.width は100% } //(canvasの論理領域について) //canvas解像度変更 let cr = canvas.getBoundingClientRect(); //ウィンドウが縦長にしろ横長にしろ少なくともこの解像度を持たせる let minW = 512; let minH = 448; //minW, minH の矩形は、現在のcanvas物理領域に、 if( cr.width / minW > cr.height / minH ) { console.log( "縦フィットする" ); let pixels = cr.height / minH; //縦の1論理ピクセル当たりの物理ピクセル数 canvas.width = cr.width / pixels; //同じ物理ピクセルで割って解像度を得る。 canvas.height = minH; } else { console.log( "横フィットする" ); let pixels = cr.width / minW; canvas.width = minW; canvas.height = cr.height / pixels; } //中心位置 let transX = canvas.width / this.scale / 2; let transY = -canvas.height / this.scale * this.horizon; this.cc.scale( this.scale, -this.scale ); this.cc.translate( transX, transY ); if( e ) this.draw( this.cc ); }.bind( this ); //resizex() addEventListener( "resize", resizex ); //---実行 this.anms = new Array(); resizex(); //posesからanmを作りそれぞれをつなげる if( Object.keys( this.poses ).length ) { let firstAnm; let beforeAnm; for( let name in this.poses ) { let anm = this.poses[ name ].getAnmGroup( name ); anm.next = null; //check. if( ! beforeAnm ) { firstAnm = anm; beforeAnm = anm; continue; } beforeAnm.next = anm; beforeAnm = anm; } this.anms.push( firstAnm ); } }//constructor //-- Method reset (App_20210530131152 1/7) //全体を最初からやり直す reset( e ) { this.stop(); if( window.apps ) { let idx = window.apps.indexOf( this ); window.apps.splice( idx, 1 ); window.app = new App_20210530131152( this.cc.canvas.id ); window.app.start(); window.apps.push( window.app ); } else { window.app = new App_20210530131152( this.cc.canvas.id ); window.app.start(); } } //-- Method getArray (App_20210530131152 2/7) getArray( svc_part, array ) { array.push( svc_part ); for( let i = 0; i < svc_part.children.length; i++ ) { let child = svc_part.children[ i ]; this.getArray( child, array ); } } //-- Method frame (App_20210530131152 3/7) async frame() { for( let i = 0; i < this.anms.length; i++ ) { let anm = this.anms[ i ]; //check. アニメの事前関数実行 if( ! anm.startFlg ) { console.log( " B start1", anm.name, anm.class ); anm.startFlg = true; anm.start.call( this ); anm.useNow(); } anm.frame.call( anm ); //check. アニメの終了 if( anm.endFlg ) { console.log( " B end", anm.name ); this.anms.splice( i, 1 ); i--; anm.end(); //アニメの事後関数実行 //次に続くアニメについて if( anm.next ) { console.log( " B start2", anm.next.name, anm.next.class ); anm.next.start.call( this ); if( this.testflg ) { await delay( 500 ); this.testflg = false; } anm.next.startFlg = true; this.anms.push( anm.getNext() ); } } }//for anms this.calc(); this.draw( this.cc ); }//frame() //-- Method calc (App_20210530131152 4/7) calc() { this.svcs.map( svc => { svc.calc1(); svc.calc2(); } ); } //-- Method start (App_20210530131152 5/7) start() { switch( "" ) { case "key": onkeydown = this.frame.bind( this ); break; case "one": this.draw( this.cc ); break; case "slow": this.timerId = setInterval( this.frame.bind( this ), 500 ); break; case "normal": default: this.timerId = setInterval( this.frame.bind( this ), this.timerMs ); break; } } //-- Method stop (App_20210530131152 6/7) stop() { clearInterval( this.timerId ); } //-- Method draw (App_20210530131152 7/7) draw( cc ) { this.cc.tmp.clearAll(); this.drawArray( cc, this.drawings ); cc.tmp.circle( this.tx, this.ty, 4, "magenta", "magenta" ); if( 0 ) { //画面の中心 cc.tmp.circle( 0, 0, 2, "red", "red" ); } } drawArray( cc, array ) { for( let i = 0; i < array.length; i++ ) { let drawing = array[ i ]; //check. 要素が配列ならば if( Array.isArray( drawing ) ) this.drawArray( cc, drawing ); //check. 要素が非表示ならば if( ! drawing.visibility ) continue; drawing.draw( cc ); } } }//App_20210530131152 //--Class 2/8 SVC_Part_20210530131152 class SVC_Part_20210530131152 { constructor( name ) { this.name = name; this.initialX = 0; this.initialY = 0; this.initialRotation = 0; //as A this.visibility = true; this.absoluteX = 0; this.absoluteY = 0; this.imgd = new TestRect_20210530131152( "rect" ); this.jointHash = new Object(); this.jointHash[ "原点" ] = new Joint_20210530131152( "原点", 0, 0 ); this.currentJoint = this.jointHash[ "原点" ]; this.parentJoint = null; this.parent = null; this.children = new Array(); this.adjustArgs = null; this.debug1 = false; } //-- Method addJoint (SVC_Part_20210530131152 1/12) addJoint( name, initialX, initialY ) { return this.jointHash[ name ] = new Joint_20210530131152( name, initialX, initialY ); } //-- Method connect (SVC_Part_20210530131152 2/12) connect( jointName, child, childJointName ) { //check. 自分自身を子にしようとした if( this == child ) { alert( this.name + "は、connect()において、自分自身を子にしようとした." ); return; } //check. 省略時は原点 if( childJointName == null ) { childJointName = "原点"; } //check. そのジョイント名は存在しない。 if( ! this.jointHash[ jointName ] ) { let mes = "The joint name does not exist."; mes += "joint name: " + this.name + "." + jointName; mes += "at connect()"; alert( mes ); } //check. そのジョイント名は存在しない。 if( ! child.jointHash[ childJointName ] ) { let mes = "The joint name does not exist."; mes += "joint name: " + child.name + "." + childJointName; mes += "at connect()"; alert( mes ); } this.children.push( child ); child.parent = this; child.parentJoint = this.jointHash[ jointName ]; child.currentJoint = child.jointHash[ childJointName ]; } //-- Method adjust (SVC_Part_20210530131152 3/12) adjust( fromSVC, fromJointName, toInfo ) { this.adjustArgs = { fromSVC : fromSVC, fromJoint : fromSVC.jointHash[ fromJointName ], toInfo : toInfo, } } //-- Method releaseAdjust (SVC_Part_20210530131152 4/12) releaseAdjust() { this.adjustArgs = null; } //-- Method moveTo (SVC_Part_20210530131152 5/12) moveTo( x, y ) { this.releaseAdjust(); this.initialX = x; this.initialY = y; } //-- Method resetAllRotation (SVC_Part_20210530131152 6/12) resetAllRotation() { this.initialRotation = 0; //子 this.children.map( child => child.resetAllRotation() ); } //-- Method calc1 (SVC_Part_20210530131152 7/12) calc1() { //絶対座標を計算する。 if( ! this.parent ) { //親がない場合は this.absoluteX = this.initialX; this.absoluteY = this.initialY; this.absoluteRotation = this.initialRotation; } else { //親がある場合は //check. if( ! this.parentJoint ) { alert( "undefined parentJoint at " + this.name ); } this.absoluteX = this.parentJoint.absoluteX; this.absoluteY = this.parentJoint.absoluteY; this.absoluteRotation = this.initialRotation + this.parent.absoluteRotation; //as C = A + B } //各jointの絶対座標を求める。 for( let name in this.jointHash ) { let joint = this.jointHash[ name ]; let x = joint.initialX - this.currentJoint.initialX; let y = joint.initialY - this.currentJoint.initialY; let res = this.mathRotate( x, y, this.absoluteRotation ); joint.absoluteX = this.absoluteX + res.X; joint.absoluteY = this.absoluteY + res.Y; } //子 this.children.map( child => child.calc1() ); }//calc() //-- Method calc2 (SVC_Part_20210530131152 8/12) calc2() { if( this.adjustArgs ) { //adjustの値を計算する let fromSVC = this.adjustArgs.fromSVC; let fromJoint = this.adjustArgs.fromJoint; let toInfo = this.adjustArgs.toInfo; //x, y, r 各値の移動量を計算する let adjustX, cx; if( typeof toInfo.x !== "undefined" ) { //adjustする let toX; if( typeof toInfo.x === "object" ) toX = toInfo.x.object[ toInfo.x.propertyName ]; else toX = toInfo.x; adjustX = toX - fromJoint.absoluteX; cx = toX; } else if( this.parentJoint ) { //adjustしない1 adjustX = 0; cx = this.parentJoint.absoluteX; } else { //adjustしない2 adjustX = 0; cx = this.absoluteX; } let adjustY, cy; if( typeof toInfo.y !== "undefined" ) { //adjustする let toY; if( typeof toInfo.y === "object" ) toY = toInfo.y.object[ toInfo.y.propertyName ]; else toY = toInfo.y; adjustY = toY - fromJoint.absoluteY; cy = toY; } else if( this.parentJoint ) { //adjustしない1 adjustY = 0; cy = this.parentJoint.absoluteY; } else { //adjustしない2 adjustY = 0; cy = this.absoluteY; } let adjustRotation; if( typeof toInfo.rotation !== "undefined" ) { let toR; if( typeof toInfo.rotation === "object" ) toR = toInfo.rotation.object[ toInfo.rotation.propertyName ]; else toR = toInfo.rotation; //※toRはtoSVCを0度としたときの、fromSVCの角度を指定している。 adjustRotation = toR - fromSVC.absoluteRotation; } else { adjustRotation = 0; } this.calc3( adjustX, adjustY, cx, cy, adjustRotation ); } else { this.children.map( child => child.calc2() ); } }//calc2() //-- Method calc3 (SVC_Part_20210530131152 9/12) calc3( adjustX, adjustY, cx, cy, adjustRotation ) { //絶対座標にadjustを加える this.absoluteX += adjustX; this.absoluteY += adjustY; this.absoluteRotation += adjustRotation; //as E = C + D //座標をadjust回転 let res = this.mathRotateC( cx, cy, this.absoluteX, this.absoluteY, adjustRotation ); this.absoluteX = res.X; this.absoluteY = res.Y; //各jointも座標をadjust回転 for( let name in this.jointHash ) { let joint = this.jointHash[ name ]; //仮の絶対座標にadjustを加える joint.absoluteX += adjustX; joint.absoluteY += adjustY; //※jointにはrotaionはない //座標をadjust回転 let res = this.mathRotateC( cx, cy, joint.absoluteX, joint.absoluteY, adjustRotation ); joint.absoluteX = res.X; joint.absoluteY = res.Y; } //子 this.children.map( child => child.calc3( adjustX, adjustY, cx, cy, adjustRotation ) ); }//calc3() //-- Method draw (SVC_Part_20210530131152 10/12) draw( cc ) { //自身を描画 cc.save(); //計算した絶対座標へ移動、回転 cc.translate( this.absoluteX, this.absoluteY ); cc.rotate( this.absoluteRotation ); //もともとの原点 let ox = -this.jointHash[ this.currentJoint.name ].initialX; let oy = -this.jointHash[ this.currentJoint.name ].initialY; let x = ox + this.imgd.x; let y = oy + this.imgd.y; cc.translate( x, y ); this.imgd.draw( cc ); if( this.debug1 ) { cc.scale( 1, -1 ); cc.fillStyle = "green"; cc.fillText( this.name, 16, -4 ); } cc.restore(); //子 this.children.map( child => child.draw( cc ) ); //debug. if( this.debug1 ) { //各jointを○で示す for( let name in this.jointHash ) { let joint = this.jointHash[ name ]; cc.save(); cc.translate( joint.absoluteX, joint.absoluteY ); cc.scale( 1, -1 ); // cc.globalAlpha = .3; cc.tmp.circle( 0, 0, 2, null, "red" ); cc.font = "6px''"; cc.fillStyle = "blue"; cc.fillText( name, 8, 0 ); cc.restore(); } } }//draw() //-- Method mathRotate (SVC_Part_20210530131152 11/12) mathRotate( x, y, theta2 ) { let theta1 = Math.atan2( y, x ); let hankei = Math.sqrt( x * x + y * y ); return { X : Math.cos( theta1 + theta2 ) * hankei, Y : Math.sin( theta1 + theta2 ) * hankei, } } //-- Method mathRotateC (SVC_Part_20210530131152 12/12) mathRotateC( cx, cy, x, y, theta2, flg ) { x -= cx; y -= cy; let theta1 = Math.atan2( y, x ); let hankei = Math.sqrt( x * x + y * y ); return { X : Math.cos( theta1 + theta2 ) * hankei + cx, Y : Math.sin( theta1 + theta2 ) * hankei + cy, } } }//SVC_Part_20210530131152 //--Class 3/8 TestRect_20210530131152 class TestRect_20210530131152 { constructor( type ) { this.x = 0; this.y = 0; this.w = 10; this.h = 10; this.visibility = true; this.type = type; } //-- Method draw (TestRect_20210530131152 1/1) draw( cc ) { //check. if( ! this.visibility ) return; switch( this.type ) { case "rect": cc.strokeStyle = "orange"; cc.strokeRect( 0, 0, this.w, this.h ); break; case "horizon": cc.fillStyle = "brown"; let w = 130; let h = 23; cc.fillRect( -w, -h, w * 2, h ); break; case "none": break; default: alert( "undefined type: '" + this.type + "'" ); } } }//class TestRect_20210530131152 //--Class 4/8 Joint_20210530131152 class Joint_20210530131152 { constructor( name, initialX, initialY ) { this.name = name; this.initialX = initialX; this.initialY = initialY; this.absoluteX = 0; this.absoluteY = 0; } } //--Class 5/8 Pose_20210530131152 class Pose_20210530131152 { constructor( ms, timerMs, anmdata ) { this.ms = ms; this.timerMs = timerMs; this.anmdata = anmdata; this.next = null; } //-- Method doit (Pose_20210530131152 1/2) doit() { for( let i = 0; i < this.anmdata.list.length; i++ ) { let data = this.anmdata.list[ i ]; let object = data[ 0 ]; let propertyName = data[ 1 ]; let endValue = data[ 2 ]; //check. if( this.anmdata.start ) this.anmdata.start(); if( this.anmdata.end ) this.anmdata.end(); object[ propertyName ] = endValue; }//for } //-- Method getAnmGroup (Pose_20210530131152 2/2) getAnmGroup( name ) { let anmGroup = new AnmGroup_20210530131152(); anmGroup.name = name; let tmpArray = new Array(); for( let i = 0; i < this.anmdata.list.length; i++ ) { let data = this.anmdata.list[ i ]; let object = data[ 0 ]; let propertyName = data[ 1 ]; //check. オブジェクトとプロパティの組み合わせの重複を確認 let res = true; for( let i = 0; i < tmpArray.length; i++ ) { if( tmpArray[ i ][ 0 ] == object && tmpArray[ i ][ 1 ] == propertyName ) { res = false; break; } } if( !res ) { alert( "「同時に開始されるアニメ」のリスト(" + name + ")の中で、同じオブジェクトにおいて、同じプロパティ名(" + propertyName + ")でのアニメが指定されています. 競合するので直してください. at class:Pose_20210530131152 method:getAnmGroup()" ); } let endValue = data[ 2 ]; let anm = new Anm_20210530131152( object, propertyName, endValue, this.ms, this.timerMs ); anmGroup.children.push( anm ); //check. 開始・終了メソッド定義 if( this.anmdata.start ) anmGroup.start = this.anmdata.start; if( this.anmdata.end ) anmGroup.end = this.anmdata.end; tmpArray.push( [ object, propertyName ] ); }//for return anmGroup; }//getAnmGroup() }//class Pose_20210530131152 //--Class 6/8 Anm_20210530131152 class Anm_20210530131152 { constructor( object, propertyName, endValue, ms, timerMs ) { this.name = "**"; this.class = "Anm_20210530131152"; this.object = object; this.propertyName = propertyName; //check. 指定ミスチェック if( this.propertyName in this.object == false ) { alert( "プロパティ" + this.propertyName + "はオブジェクト this.object のメンバではありません. at Anm_20210530131152.constructor" ); } this.endValue = endValue; this.ms = ms; this.timerMs = timerMs; this.useNow(); } //-- Method useNow (Anm_20210530131152 1/2) useNow() { this.startValue = this.object[ this.propertyName ]; this.endFlg = this.endValue == this.startValue; this.dir = this.endValue > this.startValue ? 1 : -1; let count = this.ms / this.timerMs; this.step = Math.abs( this.endValue - this.startValue ) / count; } //-- Method frame (Anm_20210530131152 2/2) frame() { this.object[ this.propertyName ] += this.step * this.dir; //check. if( ( this.dir > 0 && this.object[ this.propertyName ] >= this.endValue ) || ( this.dir < 0 && this.object[ this.propertyName ] <= this.endValue ) ) { this.object[ this.propertyName ] = this.endValue; this.endFlg = true; } } start() {} end() {} }//class Anm_20210530131152 //--Class 7/8 AnmGroup_20210530131152 class AnmGroup_20210530131152 { constructor( name ) { this.name = name; this.class = "AnmGroup_20210530131152"; this.children = new Array(); } //-- Method frame (AnmGroup_20210530131152 1/4) frame() { //子のframe()を実行する。 this.children.map( child => child.frame() ); //子がすべて終了なら、自身は終了。 this.endFlg = true; for( let i = 0; i < this.children.length; i++ ) { if( this.children[ i ].endFlg == false ) { this.endFlg = false; break; } } } //-- Method useNow (AnmGroup_20210530131152 2/4) useNow() { //子のuseNow()を実行する。 this.children.map( child => child.useNow() ); } //-- Method getNext (AnmGroup_20210530131152 3/4) getNext() { //check. if( ! this.next ) { return null; } this.next.useNow(); return( this.next ); } //-- Method start (AnmGroup_20210530131152 4/4) start() {} end() {} }//class AnmGroup_20210530131152 //--Class 8/8 Graph_20210530131152 class Graph_20210530131152 extends SVC_Part_20210530131152 { constructor( name, args ) { super( name ); //check. this.imgd.type = "none"; //this.initialX = 0; //画面上のx。ここにグラフ上の始点sxが来る。 //this.initialY = 0; //画面上のy。ここにグラフ上の始点syが来る。 this.f = function( x ) { return x; }; this.sx = -10; //グラフ上の始点sx this.ex = 10; //グラフ上の終点sx this.zoomX = 1; //x方向だけ引き伸ばしたいときに利用 this.zoomY = 1; //y方向だけ引き伸ばしたいときに利用 this.zoom = 1; //全体的に拡大したいときに利用 this.visibility = false; Object.assign( this, args ); //上記の内容を引数の内容で上書きしている this.jointP = this.addJoint( "jointP", 0, 0 ); //P点 Object.seal( this.jointHash.P ); //別のインスタンスへの変更を禁止 Object.seal( this.jointP ); //別のインスタンスへの変更を禁止 this.update(); } //-- Method update (Graph_20210530131152 1/3) update() { //画面上の座標 this.initialX,Y と、グラフの始点を合わせるための補正値 this.adjustX = this.sx * this.zoomX * this.zoom; this.adjustY = this.f( this.sx ) * this.zoomY * this.zoom; this.dir = this.ex >= this.sx ? 1 : -1; this.px = this.sx; //グラフ上のP点のx座標。y座標は都度計算。 } //this.pxに値を代入すると、jointHash.jointP も変更されるしくみ。 set px( xValue ) { this._px = xValue; this.jointHash.jointP.initialX = xValue * this.zoomX * this.zoom - this.adjustX; this.jointHash.jointP.initialY = this.f( xValue ) * this.zoomY * this.zoom - this.adjustY; } get px() { return this._px; } //-- Method graphXToScreenXY (Graph_20210530131152 2/3) graphXToScreenXY( graphX ) { return { x : this.initialX + graphX * this.zoomX * this.zoom - this.adjustX, y : this.initialY + this.f( graphX ) * this.zoomY * this.zoom - this.adjustY, }; } //-- Method draw (Graph_20210530131152 3/3) draw( cc ) { //グラフを画面に描く for( let graphX = this.sx; graphX <= this.ex; graphX++ ) { let sc = this.graphXToScreenXY( graphX ); //check. 原点のとき、座標軸を描く if( graphX == 0 ) { cc.tmp.line( sc.x - 50, sc.y, sc.x + 50, sc.y, "lightgray" ); cc.tmp.line( sc.x, sc.y - 50, sc.x, sc.y + 50, "lightgray" ); } //薄い青い点・ cc.tmp.circle( sc.x, sc.y, 1, "lightblue" ); } //始点にピンクの○を描く if( 0 ) cc.tmp.circle( this.initialX, this.initialY, 4, null, "magenta" ); //P点に青い○を描く let sc = this.graphXToScreenXY( this.px ); cc.tmp.circle( sc.x, sc.y, 2, "red" ); super.draw( cc ); }//draw() } function delay( ms ) { return new Promise( function( tellOk ) { setTimeout( tellOk, ms ); } ); }